/*
	This file is part of AVRCppLib.

    AVRCppLib is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AVRCppLib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AVRCppLib.  If not, see <http://www.gnu.org/licenses/>.

    Copyright (C) Maxime Lemonnier 2007-2011
 */

#include "Compatibility/USARTHardwareCompatibility.h"
#include "../../Utils/BitManipulation.h"
#include "../../CallbackServers/FastCallbackServer.h"
namespace Coms
{

namespace USART
{

#define USART_UBRR_MASK 				0x0FFFul
#define UCSRB_READ_WRITE_CONTROL_MASK	0xF8	// 0b11111000


USARTHardware::USARTHardware(uint8_t USART_RX_vect_number, uint8_t USART_UDRE_vect_number, uint8_t USART_TX_vect_number, IOAddress udr, IOAddress ubrrh, IOAddress ubrrl, IOAddress ucsra, IOAddress ucsrb, IOAddress ucsrc) :
USART_RX_vect_number(USART_RX_vect_number), USART_UDRE_vect_number(USART_UDRE_vect_number), USART_TX_vect_number(USART_TX_vect_number), udr(udr), ubrrh(ubrrh), ubrrl(ubrrl), ucsra(ucsra), ucsrb(ucsrb), ucsrc(ucsrc)
{
	configureDefaults();
}

uintmax_t USARTHardware::getBitRate()
{

	uintmax_t divider;

	if(bitIsSetInRegister(*ucsrc, UMSEL))
		divider = 2;
	else if(bitIsSetInRegister(*ucsra, U2X))
		divider = 8;
	else
		divider = 16;

	uint16_t ubrr = *ubrrl;

	ubrr += ((uint16_t)*ubrrh) << 8;

	return F_CPU /(divider * (ubrr + 1));
}


void USARTHardware::connectFrameReceivedCallback(Callback * frameReceivedCallback)
{
	FastCallbackServer::getInstance()->connect(USART_RX_vect_number, frameReceivedCallback);
}

Callback * USARTHardware::disconnectFrameReceivedCallback()
{
	return FastCallbackServer::getInstance()->disconnect(USART_RX_vect_number);
}


void USARTHardware::connectTransmitterReadyCallback(Callback * transmitterReadyCallback)
{
	FastCallbackServer::getInstance()->connect(USART_UDRE_vect_number, transmitterReadyCallback);
}

Callback * USARTHardware::disconnectTransmitterReadyCallback()
{
	return FastCallbackServer::getInstance()->disconnect(USART_UDRE_vect_number);
}


void USARTHardware::connectFrameTransmittedCallback(Callback * frameTransmittedCallback)
{
	FastCallbackServer::getInstance()->connect(USART_TX_vect_number, frameTransmittedCallback);
}

Callback * USARTHardware::disconnectFrameTransmittedCallback()
{
	return FastCallbackServer::getInstance()->disconnect(USART_TX_vect_number);
}

}

}
